/**
 * @param {string} beginWord
 * @param {string} endWord
 * @param {string[]} wordList
 * @return {number}
 */
var ladderLength = function(beginWord, endWord, wordList) {
  if(wordList.indexOf(endWord) == -1) {
      return 0;
  }
  // 判断只差一个字母的函数
  const wLen = endWord.length;
  function reach(w1, w2) {
      let dif = 0;
      for (let i in w1) {
          if (w1[i] !== w2[i]) {
              dif ++;
              if (dif > 1) {
                  return false;
              }
          }
      }
      return true;
  }

  // 第一步，构建数/图

  const hashMap = new Map();

  for (let key in [beginWord, ...wordList]) {
      let keyWord = [beginWord, ...wordList][key];
      for (let i in wordList) {
          if (reach(keyWord, wordList[i])){
              if (hashMap.has(keyWord)) {
                  hashMap.get(keyWord).push(wordList[i]);
              }
              else {
                  hashMap.set(keyWord, [wordList[i]]);
              }
          }
      }
      // 删掉自己
      if (key > 0) {
          hashMap.get(keyWord).splice(hashMap.get(keyWord).indexOf(keyWord), 1);
      }
  }

  // 第二步，最短路径，寻找最短到的路径

  // 存储到过的点，不重复访问
  const reachedWords = new Set();

  // 存储现在探索的位置，扩散探索
  let nowWords = new Set([beginWord]);

  // 存储可以探索的位置
  let reachableWords = new Set(hashMap.get(beginWord));

  // 探索次数
  let ans = 1;
  while(true) {
      ans ++;
      // 判断是否还允许继续探索
      if (reachableWords.length == 0) {
          return 0;
      }

      // 可以探索的位置是否包含目标点
      if (reachableWords.has(endWord)) {
          return ans;
      }

      // 记录添加本次探索到达过的点
      reachedWords.add.apply(reachedWords, reachableWords);

      // 达到所有探索点
      nowWords = [...reachableWords];

      // 清空所有可探索点
      reachableWords = [];

      // 新增可探索点
      for (let w of nowWords) {
          wList = hashMap.get(w);
          // 筛除已经到过的点 和 可以到达的点，防重复
          reachableWords.add.apply(reachableWords, wList.filter(item => !reachedWords.has(item)));
      }
  }
};

const beginWord = "hit";
const endWord = "cog";
const wordList = ["hot","dot","dog","lot","log","cog"];

console.log(ladderLength(beginWord, endWord, wordList));